﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using DynamicData;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LuckyFish.Ledger.Data;

namespace LuckyFish.Ledger.App.ViewModels;

public class MainWindowViewModel : ViewModelBase
{
    #region Statistics

    private void StatisticsChange()
    {
        StatisticsModels.Clear();
        Series.Clear();
        var items = AllData.Where(x =>
            DateCompare(x.CreateTime, StartStatisticsTime.ToString()) &&
            DateCompare(EndStatisticsTime.ToString(), x.CreateTime));
        var ledgerModels = items as LedgerModel[] ?? items.ToArray();
        if(!ledgerModels.Any())return;
        StatisticsModels.Add(ledgerModels);
        foreach (var category in Categories)
        {
            var a = ledgerModels.Where(x => x.Category == category.CategoryName).ToArray();
            Series.Add(LedgerToPieSeries(a,category.CategoryName));
        }
    }

    private ObservableCollection<LedgerModel> StatisticsModels { get; } = new();

    private DateTimeOffset? _startStatisticsTime = DateTimeOffset.Now.AddMonths(-1);

    public DateTimeOffset? StartStatisticsTime
    {
        get => _startStatisticsTime;
        set
        {
            SetField(ref _startStatisticsTime, value);
            StatisticsChange();
        }
    }

    private DateTimeOffset? _endStatisticsTime = DateTimeOffset.Now;

    public DateTimeOffset? EndStatisticsTime
    {
        get => _endStatisticsTime;
        set
        {
            SetField(ref _endStatisticsTime, value);
            StatisticsChange();
        }
    }

    public ObservableCollection<ISeries> Series { get; } = new ();

    #endregion

    #region ChooseProp

    private CategoryModel? _category;

    public CategoryModel? Category
    {
        get => _category;
        set
        {
            SetField(ref _category, value);
            if(value == null)return;
            Choose(value.CategoryName, false);
        }
    }

    private string? _name;

    public string? Name
    {
        get => _name;
        set
        {
            SetField(ref _name, value);
            if (value != null) Choose(value, true);
        }
    }

    private DateTimeOffset? _startTime = DateTimeOffset.Now.AddMonths(-1);

    public DateTimeOffset? StartTime
    {
        get => _startTime;
        set
        {
            SetField(ref _startTime, value);
            Choose(FromDate);
        }
    }

    private DateTimeOffset? _endTime = DateTimeOffset.Now;

    public DateTimeOffset? EndTime
    {
        get => _endTime;
        set
        {
            SetField(ref _endTime, value);
            Choose(FromDate);
        }
    }

    private decimal _utmostAmount;

    public decimal UtmostAmount
    {
        get => _utmostAmount;
        set
        {
            SetField(ref _utmostAmount, value);
            Choose(FromAmount);
        }
    }

    private decimal _leastAmount;

    public decimal LeastAmount
    {
        get => _leastAmount;
        set
        {
            SetField(ref _leastAmount, value);
            Choose(FromAmount);
        }
    }

    #endregion

    #region Prop

    public ObservableCollection<CategoryModel> Categories { get; set; } = new();
    private LedgerContext Context { get; }

    public List<string> ComboItems => new()
    {
        "From Name",
        "From Amount",
        "From Category",
        "From CreateTime"
    };

    private List<LedgerModel> AllData { get; set; } = new();

    public ObservableCollection<LedgerModel> Data { get; set; } = new();

    #endregion

    #region Init

    private void Init()
    {
        Data.Clear();
        Data.Add(AllData);
        StatisticsChange();
    }

    public void Init(IEnumerable<LedgerModel> newData)
    {
        Data.Clear();
        Data.Add(newData);
        StatisticsChange();
    }

    public void Init(List<LedgerModel> newData)
    {
        AllData = newData;
        Init();
    }

    public void Init(LedgerContext ledgerContext)
    {
        AllData = ledgerContext.Ledgers.ToList();
        Categories.Clear();
        Categories.Add(ledgerContext.Categorys);
        Init();
    }

    #endregion

    #region Choose

    private void Choose(string type, bool isChooseName)
        => Init(isChooseName ? AllData.Where(x => x.Name == type) : AllData.Where(x => x.Category == type));

    private void Choose(Func<decimal, bool> func)
        => Init(AllData.Where(x => func(x.Amount)));

    private void Choose(Func<string, bool> func)
        => Init(AllData.Where(x => func(x.CreateTime)));

    #region ChooseFunc

    private bool DateCompare(string? s1, string? s2)
    {
        if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2)) return false;
        return DateTime.Compare(DateTime.Parse(s1), DateTime.Parse(s2)) >= 0;
    }

    private Func<decimal, bool> FromAmount => arg => arg <= UtmostAmount && arg >= LeastAmount;

    private Func<string, bool> FromDate => s =>
        DateCompare(s, StartTime.ToString()) && DateCompare(EndTime.ToString(), s);

    #endregion

    #endregion

    #region DataOperation

    public void Add(LedgerModel model)
    {
        Context.Ledgers.Add(model);
        Context.SaveChanges();
        AllData.Add(model);
        Data.Add(model);
    }

    public void Add(CategoryModel model)
    {
        Context.Categorys.Add(model);
        Context.SaveChanges();
        Categories.Add(model);
    }

    public void Remove(LedgerModel model)
    {
        Context.Ledgers.Remove(model);
        Context.SaveChanges();
        AllData.Remove(model);
        Init();
    }

    #endregion

    #region Function

    private static ISeries LedgerToPieSeries(LedgerModel[] model, string name)
        => new PieSeries<decimal>
        {
            Values = new[] { model.Sum(ledgerModel => ledgerModel.Amount) },
            Name = name
        };

    #endregion

    public MainWindowViewModel()
    {
        Context = new LedgerContext();
        Init(Context);
        StatisticsChange();
    }
}